package com.baseproject.datasource;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import com.baseproject.datasource.get.procedure.DataProcedure;
import com.baseproject.datasource.get.request.type.ListRequestType;
import com.baseproject.datasource.local.LocalDataSource;
import com.baseproject.datasource.local.file.ILocalFileStrategy;
import com.baseproject.datasource.local.file.reservoir.Reservoir;
import com.baseproject.datasource.remote.BaseRemoteStrategy;
import com.baseproject.datasource.remote.RemoteDataSource;
import com.baseproject.datasource.remote.RetrofitStrategy;
import com.baseproject.json.GsonProcessor;
import com.baseproject.json.JsonUtils;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import rx.observers.TestSubscriber;
import rx.schedulers.Schedulers;

import static com.baseproject.datasource.local.LocalDataSource.MAX_SIZE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

/**
 * Created by hp on 2017/8/21.
 */
@RunWith(AndroidJUnit4.class)
public class RepositoryTest {

    public static final String KET_MY_CART = "myCart";
    public static final String KET_SAVE_PATH_MY_CART = KET_MY_CART + File.separator + KET_MY_CART;

    public static String TEST_URL = "http://1.mytaobao.applinzi.com/";
    public static String TEST_CART_URL = TEST_URL + "?action=getItemCommodityList";

    Context appContext;

    private LocalDataSource mLocalDataSource;
    private RemoteDataSource mRemoteDataSource;

    private Repository mRepository;
    private Repository mRepositorySpy;
    private TestSubscriber<Object> mTestSubscriber;
    private BaseRemoteStrategy mBaseRemoteStrategySpy;

    private ILocalFileStrategy mILocalFileStrategySpy;

    @Before
    public void init() throws Exception {
        appContext = InstrumentationRegistry.getTargetContext();
        mLocalDataSource = LocalDataSource.getInstance();
        mRemoteDataSource = RemoteDataSource.getInstance();
        mRepository = Repository.getInstance(mRemoteDataSource, mLocalDataSource);
        mTestSubscriber = new TestSubscriber<>();

        mBaseRemoteStrategySpy = spy(new RetrofitStrategy());
        mRemoteDataSource.setBaseRemoteStrategy(mBaseRemoteStrategySpy);
        Reservoir reservoir = new Reservoir();
        reservoir.init(appContext, MAX_SIZE);
        mILocalFileStrategySpy = spy(reservoir);
        mLocalDataSource.setiLocalFileStrategy(mILocalFileStrategySpy);

        mRepositorySpy = spy(mRepository);
        JsonUtils.getInstance().init(new GsonProcessor());
    }

    @Test
    public void getListRemoteOnlyNotSave() throws Exception {
        Map<String, String> params = new HashMap<String, String>() {{ put("versionCode", "100");}};
        DataProcedure remoteOnlyDataProcedure = DataProcedure.createRemoteOnly(ItemCommodity.class)
                .setIfNeedSaveToLocal(false)
                .setQueryParams(params)
                .setRequestParams(KET_SAVE_PATH_MY_CART, TEST_CART_URL)
                .setRequestType(new ListRequestType());

        startTestProcedure(remoteOnlyDataProcedure);

        verify(mBaseRemoteStrategySpy, Mockito.times(1)).getList(
                eq(remoteOnlyDataProcedure.getRemoteRequestParams().getUrl()), anyString(), eq(remoteOnlyDataProcedure.getQueryParams()));
        verify(mRepositorySpy, never()).getListFromLocalDataSource(remoteOnlyDataProcedure, remoteOnlyDataProcedure.getClassName());

        mTestSubscriber.assertValueCount(1);
        ItemCommodity itemCommodity = (ItemCommodity) mTestSubscriber.getOnNextEvents().get(0);
        assertThat(itemCommodity, notNullValue());
    }

    @Test
    public void getListRemoteFirstSave() throws Exception {
        DataProcedure dataProcedure = DataProcedure.createRemoteFirst(ItemCommodity.class)
                .setRequestParams(KET_SAVE_PATH_MY_CART, TEST_CART_URL);

        startTestProcedure(dataProcedure);

        verify(mBaseRemoteStrategySpy, Mockito.times(1)).getList(
                eq(dataProcedure.getRemoteRequestParams().getUrl()), anyString(), eq(dataProcedure.getQueryParams()));
        verify(mRepositorySpy, never()).getListFromLocalDataSource(dataProcedure, dataProcedure.getClassName());
        verify(mILocalFileStrategySpy, Mockito.times(1)).put(eq(dataProcedure.getUniqueKey()), anyObject());

        mTestSubscriber.assertValueCount(1);
        ItemCommodity itemCommodity = (ItemCommodity) mTestSubscriber.getOnNextEvents().get(0);
        assertThat(itemCommodity.isVaild(), is(true));
    }

    private void startTestProcedure(DataProcedure dataProcedure) {
        dataProcedure.setSubscribeOn(Schedulers.immediate()).setObserveOn(Schedulers.immediate());
        mRepositorySpy.getList(dataProcedure, dataProcedure.getClassName())
                .map(new CheckNullFunc1<>())
                .subscribe(mTestSubscriber);
    }


//    @Test
//    public void getListFromLocalDataSource() throws Exception {
//
//    }
//
//    @Test
//    public void getListFromRemoteDataSource() throws Exception {
//
//    }
//
//    @Test
//    public void getFile() throws Exception {
//
//    }
//
//    @Test
//    public void getFile1() throws Exception {
//
//    }
//
//    @Test
//    public void httpPostRemote() throws Exception {
//
//    }

}